package com.lagou.factory;

import com.lagou.annotion.Autowired;
import com.lagou.annotion.Comppent;
import com.lagou.annotion.Transactional;
import com.lagou.log.MLog;
import com.lagou.scan.AnnotionScanner;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
 * @Authther: mrwu
 * @date:2021/3/12-03
 * @Description:com.lagou.pojo
 */
public class BeanFactory {

    /**
     * 工厂类的任务
     * 解析xml 通过反射技术生成对应实例
     * 提供接口方法根据ID从map中取出bean
     */
    public static HashMap<String,Object> beanmap =new HashMap<>();

    /**
     * 存放类型与beanid
     */
    private static HashMap<String,Object> beantypeMap = new HashMap<>();



    //静态块 在类被加载时调用
    static {
         //dom4j 读取xml
        InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
        //创建流读取器
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputStream);//获取文档
            Element rootElement = document.getRootElement();//获取根节点
            List<Element> beansNode = rootElement.selectNodes("//bean");//获取所有bean
            //遍历进行实例化对象
           beansNode.forEach(beanNode->{
               String id = beanNode.attributeValue("id");
               String calsstype = beanNode.attributeValue("class");
               System.out.println(calsstype+"---id===="+id);
               try {
                   Class<?> aClass = Class.forName(calsstype);
                   Object o = aClass.newInstance();
                   beanmap.put(id, o);
               } catch (ClassNotFoundException e) {
                   e.printStackTrace();
               } catch (IllegalAccessException e) {
                   e.printStackTrace();
               } catch (InstantiationException e) {
                   e.printStackTrace();
               }
           });
            //获取注解生成的实例
            MLog.info("开始处理注解模式111");
            AnnotionScanner.parse(beantypeMap,beanmap, "com.lagou");
            MLog.info("zhujiemushi2222"+beanmap);
            //为对象赋值
            List<Element> propertynodes = rootElement.selectNodes("//property");

            propertynodes.forEach(element -> {
                String name = element.attributeValue("name");
                String ref = element.attributeValue("ref");

                String parentId = element.getParent().attributeValue("id");
                //获取要被赋值的对象
                Object parentObj = beanmap.get(parentId);
                //取出要被引用的对象
                Object refobj = beanmap.get(ref);

                for (Field field : parentObj.getClass().getDeclaredFields()) {
//                    System.out.println("name=="+name+"==="+field.getName()+"====type==="+field.getType());
                    if (name.equalsIgnoreCase(field.getName())){
                        field.setAccessible(true);
                        try {
                            field.set(parentObj, refobj);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }

                //获取set方法的方法名称
                String methodName = "set"+name;//
//                for (Method declaredMethod : parentObj.getClass().getDeclaredMethods()) {
//
//                    if (declaredMethod.getName().equalsIgnoreCase(methodName)){//忽略大小写进行对比
//                        System.out.println(declaredMethod.getName()+"---为对象辅值");
//                        try {
//                            declaredMethod.invoke(parentObj, refobj);
//                        } catch (IllegalAccessException e) {
//                            e.printStackTrace();
//                        } catch (InvocationTargetException e) {
//                            e.printStackTrace();
//                        }
//                    }
//
//
//                }

            });

            //处理注解模式下的对象依赖
            MLog.info("开始处理注解模式依赖");
            beanmap.forEach((key,value)->{
                //获取对象的属性，从属性中获取被@autowired注解的字段
              try {
                  for (Field field : value.getClass().getDeclaredFields()) {
                      if (field.isAnnotationPresent(Autowired.class)){
                          field.setAccessible(true);
                          //对该属性的类进行实例化
                          Class<?> type = field.getType();
                          //如果是接口则遍历bean对象看是否实现了次接口如果实现赋值
                          for (Object obj : beanmap.values()) {
                              //判断类之间有无继承关系 注意顺序不要搞反
                              if (type.isAssignableFrom(obj.getClass())){
                                  field.set(value,obj);
                                  //将值重新放入beansmap中
                                  beanmap.put(key, value);
                                  MLog.info("为"+value.toString()+"fuzhi"+obj);
                                  break;
                              }
                          }
//                          if (type.isInterface()){
//
//
//                          }
//                          else {
//                              //先从类型字典中匹配 如果没有需要初始化次类型，
//                              //从bean数组中获取同样类型的值进行赋值
//                              String o = (String) beantypeMap.get(type.getName());
//
//                              field.set(value, beanmap.get(o));
//
//                          }
                      }
                  }

              }catch (Exception e){
                  e.printStackTrace();
              }
            });

            //处理声明式事务注解,本处暂不考虑对接口注解情况 将被注解的实例换成代理对象
            beanmap.forEach((key,value)->{
                ProxyFactory proxyFactory = (ProxyFactory)BeanFactory.getBean("proxyFactory");
                Object proxy =null;
                //此时value为类的实例
              if (value.getClass().isAnnotationPresent(Transactional.class)) {
                  if (value.getClass().getAnnotatedInterfaces().length>0){//如果实现了接口就使用jdk代理
                      proxy= proxyFactory.getJDKProxy(value);
                  }else {
                      proxy = proxyFactory.getCGlibProxy(value);//使用cglib代理
                  }
                  beanmap.put(key, proxy);
              }else {
                  //遍历方法查看方法是否被注解
                  for (Method method : value.getClass().getDeclaredMethods()) {
                     if (method.isAnnotationPresent(Transactional.class)){
                         proxy = proxyFactory.getCGlibProxy(value);//使用cglib代理
                         beanmap.put(key, proxy);
                         break;
                     }
                  }
              }

            });

        } catch (DocumentException e) {
            e.printStackTrace();
        }


    }
    public static Object getBean(String beanID){

        return beanmap.get(beanID);
    }



}
